package com.ice.framework.web.util;

import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import org.springframework.cglib.beans.BeanCopier;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 浅拷贝工具，大量数据copy的情况下，会比Spring BeanUtils快，使用cglib的方式，在create触点时，生成了设置值的方式方法
 * @author wangwei
 * @Date 2024/5/13 14:36
 */
public class BeanCopierUtil {
    /**
     * BeanCopier的缓存，避免频繁创建，高效复用
     */
    private static final ConcurrentHashMap<String, BeanCopier> BEAN_COPIER_MAP_CACHE = new ConcurrentHashMap<String, BeanCopier>();

    /**
     * BeanCopier的copyBean，高性能推荐使用，增加缓存
     *
     * @param source 源文件的
     * @param target 目标文件
     */
    public static void copyBean(Object source, Object target) {
        String key = genKey(source.getClass(), target.getClass());
        BeanCopier beanCopier;
        if (BEAN_COPIER_MAP_CACHE.containsKey(key)) {
            beanCopier = BEAN_COPIER_MAP_CACHE.get(key);
        } else {
            beanCopier = BeanCopier.create(source.getClass(), target.getClass(), false);
            BEAN_COPIER_MAP_CACHE.put(key, beanCopier);
        }
        beanCopier.copy(source, target, null);
    }

    /**
     * 不同类型对象数据copylist
     *
     * @param sourceList
     * @param targetClass
     * @param <T>
     * @return
     */
    public static <T> List<T> copyListProperties(List<?> sourceList, Class<T> targetClass) throws Exception {
        if (ObjectUtil.isNotEmpty(sourceList)) {
            List<T> list = new ArrayList<T>(sourceList.size());
            for (Object source : sourceList) {
                T target = copyProperties(source, targetClass);
                list.add(target);
            }
            return list;
        }
        return Lists.newArrayList();
    }

    /**
     * 返回不同类型对象数据copy,使用此方法需注意不能覆盖默认的无参构造方法
     *
     * @param source
     * @param targetClass
     * @param <T>
     * @return
     */
    public static <T> T copyProperties(Object source, Class<T> targetClass) throws Exception {
        T target = targetClass.newInstance();
        copyBean(source, target);
        return target;
    }

    /**
     * @param srcClazz 源class
     * @param tgtClazz 目标class
     * @return string
     */
    private static String genKey(Class<?> srcClazz, Class<?> tgtClazz) {
        return srcClazz.getName() + tgtClazz.getName();
    }
}
